package com.jy.api.domain;

import com.jy.api.exception.MyException;
import com.jy.api.signUpReq.ScanCodeSignUpReq;
import com.jy.api.signUpReq.pos.CreateOrderReq;
import com.jy.api.signUpReq.pos.OrderItemSignUpReq;
import com.jy.api.signUpReq.pos.PaymentSignUpReq;
import com.jy.api.util.Md5Util;
import com.jy.api.util.MyDateUtils;
import com.jy.api.util.UuidUtil;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.annotations.Where;

import javax.persistence.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

/**
 * Created by hanxi on 2017/7/17.
 * 订单表
 */
@Slf4j
@Entity
@Data
@NoArgsConstructor
public class Order {
    @Id
    @Column(length = 50)
    private String id;
    private String storeId;
    private String memberId;
    private String memberName;
    private String creatorId;
    private String creatorName;
    private String code;
    private double total = 0;
    private int count = 0;
    private double discount = 0;
    private double amount = 0;

    @Enumerated(EnumType.STRING)
    private OrderStatus status;
    @Enumerated(EnumType.STRING)
    private OrderSource source;
    @Enumerated(EnumType.STRING)
    private OrderType type;

    private double removeZero;

   private double  rechargeAmount;

    /**
     * 退单时间
     *
     * @deprecated 退单会生成新的订单记录，不允许修改已有订单
     */
    @Temporal(TemporalType.TIMESTAMP)
    private Date refundTime;

    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
    @Where(clause = "`enabled`=1")
    @OrderBy(value = "addTime")
    @JoinColumn(name = "order_id")
    private List<OrderItem> items = new ArrayList<>();






    /**
     * 座位号
     */
    private String tableNo;
    @Column(insertable = false, updatable = false)
    @Temporal(TemporalType.TIMESTAMP)
    private Date addTime;
    @Column(insertable = false, updatable = false)
    @Temporal(TemporalType.TIMESTAMP)
    private Date updateTime;
    private boolean enabled = true;
    /**
     * 支付时间
     */
    private Date paymentTime;
    /**
     * 支付渠道
     */
    private String channel;

    /**
     * 商品出入库状态
     */
    private boolean stock = false;


    /**
     * 备注
     */
    private String notes;
    /**
     * 退单原因
     */
    private String refundReason;
    /**
     * 关联订单id。比如退单的原始订单id
     */
    private String refOrderId;

    private String numName;

    private String partitionName;

    private int parId;

    private int numId;

    private boolean statusFinish = false;

    //初始化订单
    public Order(String id, String creatorId, String creatorName) {
        this.id = id;
        this.creatorId = creatorId;
        this.creatorName = creatorName;
        this.status = OrderStatus.FINISHED;
        this.source = OrderSource.POS;
        this.type = OrderType.SALES;
        this.stock = true;
    }

    //初始化会员充斥订单
    public Order(String id, String storeId, String creatorId, String creatorName,
                 String productId, String productName, double amount,
                 double depositAmount, double salesPrice) {

        amount = Math.rint(amount * 100) / 100d;
        depositAmount = Math.rint(depositAmount * 100) / 100d;
        salesPrice = Math.rint(salesPrice * 100) / 100d;
        this.id = id;
        this.code = Md5Util.encrypt16(id);
        this.storeId = storeId;
        this.creatorId = creatorId;
        this.creatorName = creatorName;
        this.status = OrderStatus.INIT;
        this.source = OrderSource.POS;
        this.type = OrderType.MEMBER_DEPOSIT;
        this.amount = amount;
        this.total =  amount;
        this.discount = 0;
        this.count = 1;
        this.rechargeAmount=depositAmount;
        if (StringUtils.isNotBlank(productId)) {
            OrderItem orderItem = new OrderItem(UuidUtil.getUuid(),
                    productId, productName, salesPrice, amount,
                    1, 0, "");
            this.items.add(orderItem);
        }
    }

    //初始化订单
    public Order(String id, String storeId, String creatorId, String creatorName,
                 OrderSource source, CreateOrderReq req) {
        this.id = id;
        this.storeId = storeId;
        this.creatorId = creatorId;
        this.creatorName = creatorName;
        this.status = OrderStatus.INIT;
        this.source = source;
        this.type = OrderType.SALES;
        this.partitionName = req.getPartitionName();
        this.numName = req.getNumName();
        this.parId = req.getParId();
        this.numId = req.getNumId();


    }

    //初始化订单
    public Order(String id, String storeId, String creatorId, String creatorName,
                 OrderSource source, double amount) {
        this.id = id;
        this.storeId = storeId;
        this.creatorId = creatorId;
        this.creatorName = creatorName;
        this.status = OrderStatus.FINISHED;
        this.source = source;
        this.type = OrderType.SALES;
        this.amount = amount;
        this.count = 1;
        this.discount = 0.0;
        this.total = amount;
    }


    public void addSetMeal(SetMeal meal) {
        total += meal.getPrice();
        count += 1;
        amount += meal.getPrice();

    }


    public void addSetMealItem(SetMeal meal, int qty) {
        //查看同类商品是否已选中
        HashMap<String, OrderItem> countMap = new HashMap<>();
        for (OrderItem item : items) {
            String key = String.format("%s%s%s", item.getSetMealId(), item.getSpec(), item.isAlready());
            countMap.put(key, item);
        }
        String productKey = String.format("%s%s%s", meal.getId(), qty, false);
        if (countMap.containsKey(productKey)) {
            OrderItem item = countMap.get(productKey);
            item.setQuantity(item.getQuantity() + qty);
            item.setDealPrice(item.getDealPrice() + meal.getPrice());
            item.accuracy();
            countMap.put(productKey, item);
        } else {
            OrderItem item = new OrderItem(UuidUtil.getUuid(), meal, qty);
            item.setDealPrice(item.getDealPrice() + meal.getPrice());
            item.setSpec(1);
            item.setLabel(true);
            if (meal.isKitchenPrintEnabled()){
                item.setPort(meal.getPort());
                item.setIpAddress(meal.getIpAddress());
            }
            item.accuracy();
            countMap.put(productKey, item);
            this.items.add(item);
        }
    }

    /**
     * 添加商品明细
     *
     * @param product
     * @param orderItemSignUpReq
     * @return
     */
    public void addClerKItem(Product product, OrderItemSignUpReq orderItemSignUpReq, Order order) {
        double price = 0.0;
        double dis = 0.0;
        double original = 0.0;
        if (product.getSpecs().size() == 0) {
            if (memberId != null && product.isMemberShow() && product.isDisShow() && MyDateUtils.judgeDateSize(product.getNowHours(), product.getTomorrowHour())) {
                price = Math.rint((product.getDisPrice() * product.getMemberPrice()) * orderItemSignUpReq.getProductCount() * 100) / 100d;
                dis = Math.rint((product.getSalesPrice() * orderItemSignUpReq.getProductCount() - (product.getDisPrice() * product.getMemberPrice()) * orderItemSignUpReq.getProductCount()) * 100) / 100d;
                original = Math.rint(product.getSalesPrice() * orderItemSignUpReq.getProductCount() * 100) / 100d;
            } else if (product.isDisShow() && MyDateUtils.judgeDateSize(product.getNowHours(), product.getTomorrowHour())) {
                price = Math.rint((product.getDisPrice() * product.getSalesPrice()) * orderItemSignUpReq.getProductCount() * 100) / 100d;
                dis = Math.rint((product.getSalesPrice() * orderItemSignUpReq.getProductCount() - (product.getDisPrice() * product.getSalesPrice()) * orderItemSignUpReq.getProductCount()) * 100) / 100d;
                original = Math.rint(product.getSalesPrice() * orderItemSignUpReq.getProductCount() * 100) / 100d;
            } else if (memberId != null && product.isMemberShow()) {
                price = Math.rint(product.getMemberPrice() * orderItemSignUpReq.getProductCount() * 100) / 100d;
                original = Math.rint(product.getSalesPrice() * orderItemSignUpReq.getProductCount() * 100) / 100d;
                dis = Math.rint(((product.getSalesPrice() * orderItemSignUpReq.getProductCount()) - (product.getMemberPrice() * orderItemSignUpReq.getProductCount())) * 100) / 100d;
            } else {
                price = Math.rint(product.getSalesPrice() * orderItemSignUpReq.getProductCount() * 100) / 100d;
                original = Math.rint(product.getSalesPrice() * orderItemSignUpReq.getProductCount() * 100) / 100d;
            }
        } else {
            price = orderItemSignUpReq.getAmount();
            original = orderItemSignUpReq.getAmount();
        }
        if (order.isStatusFinish()) {
            order.setStatusFinish(false);
        }
        HashMap<String, OrderItem> countMap = new HashMap<>();
        for (OrderItem item : order.getItems()) {
            String key = String.format("%s%s%s", item.getProductId(), item.getSpec(), item.isAlready());
            countMap.put(key, item);
        }
        String productKey = String.format("%s%s%s", orderItemSignUpReq.getProductId(), orderItemSignUpReq.getProductCount(), false);
        if (countMap.containsKey(productKey)) {
            OrderItem item = countMap.get(productKey);
            item.setQuantity(item.getQuantity() + orderItemSignUpReq.getProductCount());
            item.setDealPrice(item.getDealPrice() + price);
            item.accuracy();
            countMap.put(productKey, item);
        } else {
            OrderItem i = new OrderItem(UuidUtil.getUuid(), product, orderItemSignUpReq.getProductCount());
            i.setDealPrice(i.getDealPrice() + price);
            i.setKitchenPrintEnabled(product.isKitchenPrintEnabled());
            if (product.isKitchenPrintEnabled()){
                i.setIpAddress(product.getIpAddress());
                i.setPort(product.getPort());
            }
            i.accuracy();
            countMap.put(productKey, i);
            this.items.add(i);
        }
        amount += price;
        total += original;
        count += orderItemSignUpReq.getProductCount();
        discount += dis;
        discount = ((int) Math.rint(discount * 100)) / 100d;
        amount = ((int) Math.rint(amount * 100)) / 100d;
        total = ((int) Math.rint(total * 100)) / 100d;
    }


    public void removeSetMealItem(OrderItemSignUpReq req, SetMeal meal) {
        double price = (req.getProductCount() * meal.getPrice());
        HashMap<String, OrderItem> countMap = new HashMap<>();
        for (OrderItem item : items) {
            String key = String.format("%s%s%s", item.getSetMealId(), item.getSpec(), item.isAlready());
            countMap.put(key, item);
        }
        String mealKey = String.format("%s%s%s", meal.getId(), req.getProductCount(), req.isAlready());
        if (countMap.containsKey(mealKey)) {
            OrderItem item = countMap.get(mealKey);
            if (req.getProductCount() > item.getQuantity()) {
                throw new MyException("修改失败！套餐修减数量不足！");
            }
            item.setDealPrice(item.getDealPrice() - price);
            item.setQuantity(item.getQuantity() - req.getProductCount());
            if (item.getQuantity() == 0) {
                item.setEnabled(false);
            }
            amount -= price;
            total -= price;
            count -= req.getProductCount();
        }
        amount = ((int) Math.rint(amount * 100)) / 100d;
        total = ((int) Math.rint(total * 100)) / 100d;
    }


    /**
     * 移除订单明细项
     *
     * @param
     * @param price
     * @param quantity
     */
    public void removeItem(double price, int quantity, boolean deduction, Product product, boolean already) {
        double dis = 0.0;
        if (product.getSpecs().size() == 0) {
            if (memberId != null && product.isMemberShow() && product.isDisShow() && MyDateUtils.judgeDateSize(product.getNowHours(), product.getTomorrowHour())) {
                price = (product.getDisPrice() * product.getMemberPrice()) * quantity;
                dis = (product.getSalesPrice() * quantity) - (product.getMemberPrice() * product.getDisPrice() * quantity);
            } else if (product.isDisShow() && MyDateUtils.judgeDateSize(product.getNowHours(), product.getTomorrowHour())) {
                dis = (product.getSalesPrice() * quantity) - (product.getSalesPrice() * product.getDisPrice() * quantity);
            } else if (memberId != null && product.isMemberShow()) {
                price = (product.getMemberPrice() * quantity);
                dis = (product.getSalesPrice() * quantity) - (product.getMemberPrice() * quantity);
            }
        }
        HashMap<String, OrderItem> countMap = new HashMap<>();
        for (OrderItem item : items) {
            String key = String.format("%s%s%s", item.getProductId(), item.getSpec(), item.isAlready());
            countMap.put(key, item);
        }
        String productKey = String.format("%s%s%s", product.getId(), quantity, already);
        if (countMap.containsKey(productKey)) {
            OrderItem i = countMap.get(productKey);
            i.setQuantity(i.getQuantity() - quantity);
            i.setDealPrice(i.getDealPrice() - price);
            if (i.getQuantity() == 0) {
                i.setEnabled(false);
            }
            if (deduction) {
                amount -= price;
            } else {
                discount -= price;
            }
            total -= price;
            discount -= dis;
            count -= quantity;
        }
        discount = ((int) Math.rint(discount * 100)) / 100d;
        amount = ((int) Math.rint(amount * 100)) / 100d;
        total = ((int) Math.rint(total * 100)) / 100d;
    }


    /**
     * 获取订单所有商品Id
     *
     * @return
     */
    public List<String> getProductIds() {
        List<String> productIds = new ArrayList<>();
        for (OrderItem item : items) {
            productIds.add(item.getProductId());
        }
        return productIds;
    }

    /**
     * 优惠卷使用
     */
    public void handleCoupon(double dealAmount) {
        amount = amount - dealAmount;
        discount = discount + dealAmount;
        discount = ((int) Math.rint(discount * 100)) / 100d;
        amount = ((int) Math.rint(amount * 100)) / 100d;
        total = ((int) Math.rint(total * 100)) / 100d;
    }

    /**
     * 优惠卷取消
     */
    public void relieveCoupon(double price) {
        amount = amount + price;
        discount = discount - price;
        discount = ((int) Math.rint(discount * 100)) / 100d;
        amount = ((int) Math.rint(amount * 100)) / 100d;
        total = ((int) Math.rint(total * 100)) / 100d;
    }


    /**
     * 获取订单状态
     *
     * @return
     */
    public String getStatusMsg() {
        String msg = "订单状态已锁定";
        if (OrderStatus.FINISHED == status || OrderStatus.UNFINISHED == status) {
            msg = "订单已支付";
        } else if (OrderStatus.NOTSURE == status) {
            msg = "订单支付中！请核实！(由于网络原因！如已核实请等待！)";
        } else if (OrderStatus.FAIL == status) {
            msg = "订单支付失败！请重新选择支付方式！";
        }
        return msg;
    }

    /**
     * 轮询提示
     *
     * @return
     */
    public String getMsg() {
        String msg = "";
        if (OrderStatus.FAIL == status) {
            msg = "订单支付失败,请更换支付方式";
        } else if (OrderStatus.CANCELED == status) {
            msg = "订单已取消！";
        }
        return msg;
    }


    /**
     * 判断订单支付状态是否失败
     *
     * @return
     */
    public boolean checkOrderStatusFail() {
        if (status == OrderStatus.NOTSURE &&
                new Date().getTime() - updateTime.getTime() < 1000 * 60 * 10) {
            return true;
        }
        return false;
    }

    /**
     * 判断订单是否为已支付状态
     *
     * @return
     */
    public boolean checkOrderPayStatus() {
        if (status == OrderStatus.UNFINISHED ||
                status == OrderStatus.FINISHED) {
            return true;
        }
        return false;
    }


    /**
     * 判断订单是否可以支付
     *
     * @return
     */
    public boolean checkOrderPay() {
        if (status == OrderStatus.INIT ||
                status == OrderStatus.UNSETTLED ||
                status == OrderStatus.NOTSURE ||
                status == OrderStatus.FAIL) {
            return true;
        }
        return false;
    }

    /**
     * 订单支付校验
     *
     * @return
     */
    public String payOrderJudge() {
        String msg = null;
        if (amount <= 0) {
            msg = "支付失败！支付金额必须大于0！";
        }
        if (items.size() <= 0) {
            msg = "支付失败！购买商品为空！";
        }
        return msg;
    }

    /**
     * 静态码支付校验
     *
     * @return
     */
    public String staticPayCheck(double amount, PaymentChannel channel) {
        String msg = null;
        if (this.amount != amount) {
            msg = "支付失败！支付金额与订单金额不一致!";
        } else if (total <= 0 && count <= 0) {
            msg = "支付失败！订单总额小于等于0!";
        } else if (type == OrderType.MEMBER_DEPOSIT && StringUtils.isBlank(memberId)) {
            msg = "支付失败！当前订单无会员信息!";
        } else if (channel == PaymentChannel.MEMBER &&
                type == OrderType.MEMBER_DEPOSIT) {
            msg = "支付失败！会员充值不支持会员支付!";
        } else if (status == OrderStatus.FINISHED || status == OrderStatus.UNFINISHED) {
            msg = "订单已支付！请勿重复操作!";
        } else if (status == OrderStatus.REFUNDED) {
            msg = "支付失败！订单已退单!";
        } else if (channel == PaymentChannel.MEMBER && StringUtils.isBlank(memberId)) {
            msg = "支付失败！请添加会员";
        }
        return msg;
    }

    /**
     * 移除订单明细项
     */
    public void removeOrderItem() {
        List<OrderItem> items1 = new ArrayList<>();
        for (OrderItem item : items) {
            if (!item.isEnabled()) {
                items1.add(item);
            }
        }
        items.removeAll(items1);
    }

    public void removeAllOrderItem() {
        List<OrderItem> items1 = new ArrayList<>();
        for (OrderItem item : items) {
            if (item.isEnabled()) {
                items1.add(item);
            }
        }
        items.removeAll(items1);
    }


    public String checkAddOrder() {
        String msg = null;
        //判断订单状态
        if (status == OrderStatus.UNFINISHED || status == OrderStatus.FINISHED) {
            msg = "订单已支付成功！";
        } else if (status == OrderStatus.CANCELED) {
            msg = "订单已取消！";
        } else if (status == OrderStatus.REFUNDED) {
            msg = "订单已退！";
        } else if (status == OrderStatus.NOTSURE) {
            msg = "订单支付中！";
        } else if (status == OrderStatus.FAIL) {
            msg = "订单支付失败！请取消订单或继续支付！";
        }
        return msg;
    }


    public Order(Order order) {
        this.id = UuidUtil.getUuid();
        this.storeId = order.getStoreId();
        if (null == order.getMemberId()) {
            this.memberId = null;
            this.memberName = null;
        } else {
            this.memberId = order.getMemberId();
            this.memberName = order.getMemberName();
        }
        this.creatorId = order.getCreatorId();
        this.creatorName = order.getCreatorName();
        this.code = order.getCode();
        this.total = order.getTotal();
        this.count = order.getCount();
        this.discount = order.getDiscount();
        this.amount = order.getAmount();
        this.status = order.getStatus();
        this.source = order.getSource();
        this.type = order.getType();
        this.removeZero = order.getRemoveZero();
        this.tableNo = order.getTableNo();
        this.addTime = order.getAddTime();
        this.updateTime = order.getUpdateTime();
        this.stock = order.isStock();
        this.numName = order.getNumName();
        this.partitionName = order.getPartitionName();
        this.parId = order.getParId();
        this.numId = order.getNumId();
        this.statusFinish = order.isStatusFinish();
        this.rechargeAmount=order.getRechargeAmount();
        List<OrderItem> items = new ArrayList<>();
        for (OrderItem item : order.getItems()) {
            OrderItem orderItem = new OrderItem(item);
            items.add(orderItem);
        }
        this.items = items;
    }

}
